package org.shop.util;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import javax.servlet.http.Part;

/**
 * 文件上传
 * 
 * @author zqx
 * @date 2021-12-12
 */
public class FileUploadUtil {

	/**
	 * 上传文件最大容量
	 */
	private long maxSize;

	/**
	 * 设置允许上传文件的类型
	 */
	private List<String> allowFileExt = new ArrayList<String>();

	/**
	 * <p>
	 * 设置默认容量和默认允许上传的文件
	 * </p>
	 * <p>
	 * 默认允许上传1MB的文件
	 * </p>
	 * <p>
	 * 默认允许上传的文件类型有：doc、docx、xls、xlsx、pdf、jpg、jpeg、png、gif、rar、zip
	 * </p>
	 */
	public FileUploadUtil() {
		// 默认允许上传1MB的文件
		this.maxSize = 1 * 1024 * 1024;
		this.setAllowFileExt("doc,docx,xls,xlsx,pdf,jpg,jpeg,png,gif,rar,zip");
	}

	/**
	 * 指定最大容量和允许上传文件
	 * 
	 * @param maxSize      最大容量
	 * @param allowFileExt 允许上传文件扩展名，逗号分隔
	 */
	public FileUploadUtil(long maxSize, String allowFileExt) {
		this.maxSize = maxSize;
		this.setAllowFileExt(allowFileExt);
	}

	public long getMaxSize() {
		return maxSize;
	}

	/**
	 * 设置文件最大容量，默认单位为字节
	 * 
	 * @param maxSize
	 */
	public void setMaxSize(long maxSize) {
		this.maxSize = maxSize;
	}

	public List<String> getAllowFileExt() {
		return allowFileExt;
	}

	/**
	 * 设置允许上传文件类型。支持多个，使用英文逗号分隔
	 * 
	 * @param ext
	 */
	public void setAllowFileExt(String ext) {
		if (ext != null && !"".equals(ext)) {
			this.allowFileExt.clear();
		}
		String[] str = ext.split(",");
		for (String s : str) {
			this.allowFileExt.add(s);
		}
	}

	/**
	 * 获取上传原文件名
	 * 
	 * @param header
	 * @return
	 */
	private String getFilename(String header) {
		String filename = "";
		int beginIndex = header.indexOf("filename=\"") + 10;
		int endIndex = header.lastIndexOf("\"");
		filename = header.substring(beginIndex, endIndex);
		return filename;
	}

	/**
	 * 创建UUID字符串
	 * 
	 * 使用这个字符串作为上传文件的名称，以防止上传文件被替换
	 * 
	 * @return
	 */
	private String createUUID() {
		return UUID.randomUUID().toString().replace("-", "");
	}

	/**
	 * 获取上传文件扩展名
	 * 
	 * @param filename 文件名称
	 * @return 文件后缀（扩展名）
	 */
	private String getFileExt(String filename) {
		String value = "";

		if (filename == null || filename.lastIndexOf('.') != -1 && filename.lastIndexOf('.') == filename.length() - 1) {
			return "";
		}

		int beginIndex = filename.lastIndexOf('.') + 1;
		int endIndex = filename.length();
		value = filename.substring(beginIndex, endIndex);

		return value;
	}

	/**
	 * 上传文件，文件名为UUID
	 * 
	 * @param part
	 * @param path
	 * @return 返回上传文件名
	 */
	public String upload(Part part, String path) {
		// 获取头信息 
		String header = part.getHeader("Content-Disposition");
		
		// 获取上传文件的原文件名
		String filename = this.getFilename(header);
		
		// 获取上传文件的后缀
		String ext = this.getFileExt(filename);
		
		// 重新命名上传文件的名称，以防止上传文件被替换
		String newFilename = createUUID() + "." + ext;
		
		// 调用重载文件，实现文件上传，返回上传成功的文件名称
		return upload(part, path, newFilename);
	}

	/**
	 * 上传文件
	 * 
	 * @param part
	 * @param path
	 * @param flag flag为true,则文件为名UUID，flag为false，则文件名为原文件名
	 * @return 返回上传文件名
	 */
	public String upload(Part part, String path, boolean flag) {
		String header = part.getHeader("Content-Disposition");
		String filename = this.getFilename(header);
		String ext = this.getFileExt(filename);
		String newFilename = createUUID() + "." + ext;

		if (!flag) {
			return upload(part, path, newFilename);
		}
		return upload(part, path, filename);
	}

	/**
	 * 上传文件，文件名由用户指定
	 * 
	 * @param part 上传对象
	 * @param path 上传路径
	 * @param file 上传文件名称
	 * @return
	 */
	public String upload(Part part, String path, String file) {
		// 判断是否允许上传文件容量大小
		if (part.getSize() > this.getMaxSize()) {
			throw new RuntimeException("上传文件容量溢出，只能上传" + this.getMaxSize() / 1024 * 1024 + "字节文件");
		}

		// 获取文件后缀
		String ext = this.getFileExt(file);

		// 判断是否允许上传文件类型
		if (!this.getAllowFileExt().contains(ext)) {
			throw new RuntimeException("上传失败，只能上传文件的类型有：" + this.getAllowFileExt().toString());
		}

		// 创建上传目录
		File uploadPath = new File(path);
		if (!uploadPath.exists()) {
			uploadPath.mkdirs();
		}

		// 获取上传文件路径
		String uploadFile = path + File.separator + file;

		try {
			part.write(uploadFile);
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		return file;
	}
}
